package api

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net/http"
	"reflect"
)

type BaseApi struct {
}

func (api *BaseApi) OK(data any, c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"code": 20000, "data": data, "msg": "success"})
}

func (api *BaseApi) OKMap(data gin.H, c *gin.Context) {
	data["code"] = 20000
	data["msg"] = "success"
	c.JSON(http.StatusOK, data)
}

func (api *BaseApi) FailCodeMsg(code int, msg string, c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"code": code, "data": nil, "msg": msg})
}

func (api *BaseApi) FailCodeMsgAny(code int, msg any, c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"code": code, "data": nil, "msg": msg})
}

func (api *BaseApi) handlerGrpcError(err error, c *gin.Context) {
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				{
					api.FailCodeMsg(http.StatusNotFound, e.Message(), c)
				}
			case codes.Internal:
				{
					api.FailCodeMsg(http.StatusInternalServerError, "内部错误", c)
				}
			case codes.InvalidArgument:
				{
					api.FailCodeMsg(http.StatusInternalServerError, "参数错误", c)
				}
			case codes.Unavailable:
				{
					api.FailCodeMsg(http.StatusInternalServerError, "用户服务不用", c)
				}
			default:
				{
					api.FailCodeMsg(http.StatusInternalServerError, e.Message(), c)
				}

			}
		}
	}
}

/**
 * 复制
 * @author feige
 * @date 2024-04-07
 * @version 1.0
 * @desc
 */
func (api *BaseApi) CopyProperties(dst, src interface{}) (err error) {
	// 防止意外panic
	defer func() {
		if e := recover(); e != nil {
			err = errors.New(fmt.Sprintf("%v", e))
		}
	}()

	dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
	srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)

	// dst必须结构体指针类型
	if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
		return errors.New("dst type should be a struct pointer")
	}

	// src必须为结构体或者结构体指针，.Elem()类似于*ptr的操作返回指针指向的地址反射类型
	if srcType.Kind() == reflect.Ptr {
		srcType, srcValue = srcType.Elem(), srcValue.Elem()
	}
	if srcType.Kind() != reflect.Struct {
		return errors.New("src type should be a struct or a struct pointer")
	}

	// 取具体内容
	dstType, dstValue = dstType.Elem(), dstValue.Elem()

	// 属性个数
	propertyNums := dstType.NumField()

	for i := 0; i < propertyNums; i++ {
		// 属性
		property := dstType.Field(i)
		// 待填充属性值
		propertyValue := srcValue.FieldByName(property.Name)

		// 无效，说明src没有这个属性 || 属性同名但类型不同
		if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
			continue
		}

		if dstValue.Field(i).CanSet() {
			dstValue.Field(i).Set(propertyValue)
		}
	}

	return nil
}
